S01-01 Servlet-Tomcat
[TOC]
概述
概念定义
Apache Tomcat 是由 Apache 软件基金会(ASF)主导维护的开源 Web 服务器与 Java Servlet 容器。它完全使用 Java 语言开发,实现了 Java EE / Jakarta EE 的核心 Web 规范,是将动态 Java 业务代码转化为 Web 服务的核心基础设施。
核心定位:在 Web 系统架构中,不同服务器软件承担着差异化的职责:
- Web 服务器:如 Nginx,专长于静态文件分发、网络反向代理及高并发连接调度,无法直接解析 Java 业务逻辑。
- Servlet 容器:如 Tomcat,具备基础 HTTP 通信能力,核心价值在于提供 Java 组件运行环境,管理组件生命周期并桥接网络与代码。
- 全功能应用服务器:如 WebLogic、WildFly,完整实现 EJB、JMS、JTA 等全套企业级规范,属于重量级平台。
| 服务器类型 | 典型代表 | 核心优势 | 业务场景 |
|---|---|---|---|
| Web 服务器 | Nginx, Apache HTTPD | 高并发连接、静态资源加速、负载均衡 | 反向代理、流量网关 |
| Servlet 容器 | Apache Tomcat, Jetty | 轻量、灵活、专注 Web 核心规范 | 动态 Java Web 应用 |
| 全功能应用服务器 | WebLogic, WildFly | 完整支持全套企业级 Java EE 规范 | 重型企业级传统系统 |
Tomcat 专注于 Web 相关规范的实现,主要涵盖以下四项技术标准:
- Servlet 规范:定义处理 HTTP 请求和返回响应的核心 Java 接口与抽象类。
- JSP(JavaServer Pages)规范(过时):支持在 HTML 中嵌入 Java 脚本,Tomcat 内部集成了 Jasper 引擎负责将页面编译为 Servlet 类。
- EL(Expression Language)表达式(过时):提供在视图模板中简洁访问后台数据的语法支持。
- WebSocket 规范:提供低延迟、双向全双工的长连接通信机制。
核心功能:Tomcat 在系统运行过程中主要承担四大底层能力:
通信协议解析:监听指定端口,接收客户端 TCP 连接并高效解包 HTTP 报文。
生命周期管理:负责 Servlet 实例的创建、初始化、请求调用与销毁回收。
会话状态追踪:维护客户端与服务端的 Session 状态,支持 Cookie 注入与 URL 路径重写。
安全隔离机制:通过独立的类加载器体系隔离不同 Web 应用,避免类版本冲突。
java// 容器在应用启动时负责初始化组件并注入配置 // 在服务停止或卸载应用时负责释放系统资源 public class LifeCycleServlet extends GenericServlet { @Override public void init(ServletConfig config) { // 执行初始化参数加载 } @Override public void service(ServletRequest req, ServletResponse res) { // 执行核心请求分发 } @Override public void destroy() { // 执行资源回收与断开连接 } }
权限体系【靠后】
Tomcat 内置了 Realm(安全领域)认证机制,支持将用户权限数据与外部关系型数据库对接(如 JDBCRealm)。在验证客户端权限时,容器自动执行预设的 SQL 语句以核对凭据:
SELECT user_name, role_name
FROM tomcat_realm_roles
WHERE user_name = 'admin'
GROUP BY user_name, role_name;版本演进
Tomcat 的大版本与 Java 运行时及规范版本保持严格对应:
- Tomcat 8.5 / 9.0:运行于 Java 8 及以上,基于 Servlet 3.1 / 4.0 规范,包命名空间使用
javax.servlet。 - Tomcat 10.0 / 10.1:运行于 Java 11 / 17 及以上,基于 Servlet 5.0 / 6.0 规范,因 Java EE 移交 Eclipse 基金会,包命名空间全面更名迁移为
jakarta.servlet。 - Tomcat 11.0:适配 Java 21 及以上版本,支持 Servlet 6.1 规范及 JVM 虚拟线程(Virtual Threads)特性。
应用形态
在工程实践中,Tomcat 主要呈现两种部署形态:
独立运行模式(Standalone):独立安装运行 Tomcat 服务进程,将编译好的 WAR 包投递至
webapps目录,适合多应用在传统物理机或虚拟机的统一管理。内嵌运行模式(Embedded):以 Maven/Gradle 依赖形式将 Tomcat 库引入项目中(如 Spring Boot 默认模式),由应用自身通过
main方法启动内嵌实例,是当前云原生与微服务架构的主流方案。
实现 MyTomcat
实现思路:服务端基于 Java 标准库的阻塞 I/O(BIO)模式运行。服务端绑定端口后持续阻塞等待客户端接入,获取网络套接字后建立输入输出流管道。
标准的交互处理遵循以下物理流程:
- 服务端创建
ServerSocket并绑定本地监听端口。 - 调用
accept()阻塞当前执行线程,等待客户端发起 TCP 握手。 - 连接建立后,生成独立的
Socket实例。 - 从
Socket中分离出InputStream和OutputStream分别转交业务层读写。 - 交互结束后关闭流与套接字,等待下一次连接接入。
代码实现:
package p01_mytomcat;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 实现简单的 Tomcat
*/
public class MyTomcat {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8080);
while (!serverSocket.isClosed()) {
System.out.println("Socket is running at 8080...");
Socket socket = serverSocket.accept();
// 1. 读取请求报文
InputStream in = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = br.readLine()) != null && !line.isEmpty()) {
System.out.println(line);
}
// 2. 添加 HTTP/1.1 响应头和内容
BufferedReader bufferedReader =
new BufferedReader(new FileReader("C01_Tomcat/src/p01_mytomcat/hello.html"));
String buf = "";
String line2;
while ((line2 = bufferedReader.readLine()) != null) {
buf += line2 + "\n";
}
byte[] body = buf.getBytes();
String head = """
HTTP/1.1 200 OK
Content-Type: text/html;charset=utf-8
Content-Length: %d
Content:close
""".formatted(body.length);
// 3. 写入响应
OutputStream out = socket.getOutputStream();
out.write(head.getBytes());
out.write(body);
out.flush();
socket.shutdownOutput();
socket.close();
}
serverSocket.close();
}
}运行验证:
测试上述实现的步骤如下:
- 编译并运行
MyTomcat类中的main方法,控制台输出Socket is running at 8080...。 - 打开任意浏览器,访问地址:
http://localhost:8080,页面正常展示hello,this is tomcat server。 - 访问未配置的路径:
http://localhost:8080/other,页面返回404 Not Found。
网络请求服务器时序图

安装与部署
环境准备
Tomcat 的核心是用 Java 编写的 Servlet 容器,运行依赖底层的 Java 运行环境(JRE / JDK)。在安装前必须确保 JDK 版本与 Tomcat 版本严格对应。
| Tomcat 版本 | 最低 JDK 版本 | 推荐生产 JDK | 核心规范支持 |
|---|---|---|---|
| Tomcat 8.5 | Java 7 | Java 8 | Servlet 3.1, JSP 2.3 |
| Tomcat 9.0 | Java 8 | Java 8 / 11 | Servlet 4.0, JSP 2.3 |
| Tomcat 10.1 | Java 11 | Java 17 / 21 | Jakarta Servlet 6.0 |
| Tomcat 11.0 | Java 17 | Java 21 | Jakarta Servlet 6.1 |
在终端输入以下命令,确认已安装合适版本的 JDK:
java -version下载安装
生产环境与开发环境优先推荐免安装的二进制压缩包(Core 归档包),便于跨环境迁移与定制配置。
获取安装包:访问 Apache Tomcat 官方网站,在 Download 模块下载对应版本的压缩包(Windows 下载
.zip,Linux / macOS 下载tar.gz)。解压目标路径:将压缩包解压至不含空格和中文字符的系统路径下,如 Linux 的
/opt/tomcat或 Windows 的D:\develop\apache-tomcat。设置文件权限:在 Linux / macOS 系统下,必须为
bin目录下的 Shell 脚本赋予执行权限:bashchmod +x /opt/tomcat/bin/*.sh

环境变量
为使系统进程和构建工具(如 Maven、Gradle)正确定位运行环境,需要配置系统环境变量:
- JAVA_HOME:指向 JDK 的主根目录。Tomcat 启动脚本启动时会通过此变量查找
bin/java。 - CATALINA_HOME:指向 Tomcat 的安装根目录。
- PATH:将
%CATALINA_HOME%\bin(Windows)或$CATALINA_HOME/bin(Linux)加入环境变量,方便全局调用脚本。
Windows 配置示例:
- 变量名:
CATALINA_HOME - 变量值:
D:\develop\apache-tomcat-10.1.x
Linux 在 /etc/profile 或 ~/.bashrc 中追加:
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk
export CATALINA_HOME=/opt/tomcat
export PATH=$PATH:$CATALINA_HOME/bin执行 source /etc/profile 即可生效。
目录结构
解压 Tomcat 安装包后,根目录下的各子目录承载着不同的系统功能:
- bin:存放可执行脚本,如启动脚本
startup.sh/startup.bat和停止脚本shutdown.sh/shutdown.bat。 - conf:核心配置文件目录,包含服务拓扑配置
server.xml、全局 Web 配置web.xml以及权限配置tomcat-users.xml。 - lib:Tomcat 运行时及所有 Web 应用共享的 Jar 包依赖,包括 Servlet API 与 JSP API 的实现。
- logs:运行日志存放地,常见日志包括引擎主日志
catalina.out和访问日志localhost_access_log。 - webapps:默认的 Web 应用部署目录,支持 WAR 包解压和散装目录部署。
- work:Tomcat 工作缓存目录,JSP 页面在被首次访问时翻译生成的
.java源文件和编译后的.class文件均存储在此。 - temp:存放 JVM 运行期间产生的临时文件。
启停验证
Tomcat 的生命周期由 bin 目录下的可执行脚本统一调度。
执行启动脚本:
方式一:
startup- Windows 环境:双击或在命令行运行
bin/startup.bat。 - Linux / macOS 环境:在控制台运行
./bin/startup.sh。
方式二:catalina
在命令行中执行以下命令:
shcatalina run- Windows 环境:双击或在命令行运行
排查控制台乱码:Windows 下命令提示符控制台使用 GBK 编码,若日志出现乱码,需打开
conf/logging.properties,将控制台输出编码由UTF-8改为GBK:propertiesjava.util.logging.ConsoleHandler.encoding = GBK浏览器验证服务:打开浏览器,访问
http://localhost:8080。若页面展示 Apache Tomcat 默认欢迎页面,说明服务初始化成功。安全停止服务:切勿强制击杀进程(Kill -9),应在控制台运行
bin/shutdown.bat或./bin/shutdown.sh,使容器依次注销 Servlet 并释放连接池资源。Tomcat 会在8009端口监听shutdown命令。
部署方式
将打包好的 Web 应用交付给 Tomcat 时,业界通用以下三种部署方式:
方式1:静态目录/WAR 包直接部署
这是最传统的部署途径。将编译打包生成的 .war 文件或散装项目文件夹直接移动至 webapps/ 目录下。Tomcat 在运行状态下会自动扫描、解压并将其挂载为上下文(Context),访问路径默认为文件名(如 webapps/my-app.war 对应访问路径 http://localhost:8080/my-app/)。
方式2:描述符文件外置部署
该方式支持将应用程序部署在物理磁盘的任意路径,无需移动文件:
进入 Tomcat 的
conf/Catalina/localhost/目录(若不存在则手动新建)。新建独立 XML 文件,文件名即为访问路径(如
order.xml)。文件中写入指向实际物理工程的描述信息:
xml<Context docBase="/data/deploy/order-system" reloadable="false" />访问
http://localhost:8080/order即可访问/data/deploy/order-system目录下的系统。
方式3:主配置文件虚拟路径映射
直接编辑 conf/server.xml,在 <Host> 节点内新增 <Context> 子标签:
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
<Context path="/crm" docBase="D:\data\crm_project" reloadable="true" />
</Host>注意:修改
server.xml需要重启整个 Tomcat 实例,且主文件配置不当易导致全局服务无法拉起,生产环境通常采用外置部署方案。
修改端口
Tomcat 的所有网络监听端口均在安装目录下的 conf/server.xml 文件中进行统一定义与管理。
在该文件中,不同的 XML 标签分别控制着 Tomcat 的服务停机、Web 访问以及集群通信端口。修改端口时只需用文本编辑器修改对应标签的 port 属性值即可。
Tomcat 默认的监听端口为 8080。生产环境中通常需要变更为 Web 默认的 80 端口(HTTP 协议默认端口,修改后访问网址无需手动追加 :8080);或者在单机部署多个 Tomcat 时,需修改为 8081、8082 等以避免冲突。
修改监听端口:
<!-- 将默认的 8080 端口修改为标准 Web 访问端口 80 -->
<Connector port="80" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />- port:监听的物理端口号。
- connectionTimeout:等待请求连接超时时间(单位:毫秒)。
- redirectPort:当请求需要 SSL 安全通道(HTTPS)时,自动重定向的目标端口,默认为
8443。
修改关闭端口:
Tomcat 实例在本地运行期间,会启动一个 Socket 服务专门监听关闭指令(默认为 SHUTDOWN 字符串),默认端口为 8005。
修改原因为:在一台服务器上同时运行多个独立的 Tomcat 实例时,若该端口未做区分,后续启动的实例会因端口已被占用而直接崩溃报错。
<!-- 修改 Tomcat 实例关闭监听端口以避免多实例端口冲突 -->
<Server port="8006" shutdown="SHUTDOWN">- port:接收停机指令的端口。如果设置为
-1,则表示完全禁用该停机端口(仅能通过系统杀进程方式关闭,常用于强化生产安全)。 - shutdown:用于触发停机的口令文本。
重启生效:
端口修改完成后,变更并不会对正在运行的进程生效,必须重启 Tomcat 容器:
保存已修改的
conf/server.xml文件。执行
bin/shutdown.sh(Linux)或bin/shutdown.bat(Windows)停止当前实例。检查进程确认彻底退出后,执行
bin/startup.sh或bin/startup.bat重新拉起服务。浏览器访问新端口对应的地址(如
http://localhost:80)进行验证。
探活校验
部署应用后,在项目内通常配置初始化监听器或基础 Servlet 打印运行环境,校验部署是否成功生效:
// 监听容器启动事件并校验当前部署的上下文根路径
public class HealthCheckServlet extends HttpServlet {
@Override
public void init() throws ServletException {
// 通过 Servlet 上下文获取当前应用绑定的挂载路径
String mountPath = getServletContext().getContextPath();
System.out.println("System deployed at context path: " + mountPath);
}
}远程管理
Tomcat 自带了图形化的应用程序管理器(Manager App),用于实时监控内存开销、热部署 WAR 包以及启停各应用上下文。
启用远程后台管理的步骤如下:
配置操作员权限:编辑
conf/tomcat-users.xml,在<tomcat-users>节点内添加管理角色与管理员用户:xml<role rolename="manager-gui"/> <role rolename="admin-gui"/> <user username="admin" password="SecretPassword" roles="manager-gui,admin-gui"/>解除本地访问限制:Tomcat 默认限制 Manager 只能在本地(127.0.0.1)访问。如需远程访问,需编辑
webapps/manager/META-INF/context.xml,将 Valve 的allow属性调整为允许的远程 IP 正则表达式,或注释掉 Valve 节点。访问管理面板:浏览器输入
http://<服务器IP>:8080/manager/html,输入配置好的账密即可进入管理视图。
在企业级安全架构中,若使用数据库进行统一权限管理,可以通过 JDBCRealm 直接连接数据源进行授权:
SELECT role_name, COUNT(*)
FROM tomcat_user_roles
WHERE user_name = 'admin'
GROUP BY role_name;生产运维
在 Linux 生产环境中,通常将 Tomcat 托管给 systemd 服务,以实现开机自启和异常崩溃自动重启:
创建服务描述文件
/etc/systemd/system/tomcat.service:ini[Unit] Description=Apache Tomcat Web Application Container After=network.target [Service] Type=forking Environment=JAVA_HOME=/usr/lib/jvm/java-17-openjdk Environment=CATALINA_HOME=/opt/tomcat ExecStart=/opt/tomcat/bin/startup.sh ExecStop=/opt/tomcat/bin/shutdown.sh User=tomcat Group=tomcat [Install] WantedBy=multi-user.target重载服务配置并启动:
bashsystemctl daemon-reload systemctl enable --now tomcat
HTTP
IDEA 中的 Web 项目
在 IntelliJ IDEA 中,Web 项目并非一个孤立的文件包,而是由项目管理模型、框架特征与编译产物协同构成的有机整体:
- Project 与 Module:IDEA 的 Project 相当于工作空间(Workspace),而具体的业务系统以 Module(模块)为单位存在。一个 Project 下可挂载多个相互独立的 Web Module。
- Facet(刻面):用于向 IDEA 声明当前模块具备某种技术栈规范(如 Web、Spring)。配置了 Web Facet 后,IDEA 才会识别
web.xml并启用上下文路径补全及 Servlet 语法提示。 - Artifact(工件/产物):模块源码、静态资源与第三方依赖编译打包后的最终形态,是直接交付给 Tomcat 等 Servlet 容器运行的实体。
创建 Web 项目
在 IDEA 中初始化一个标准 Web 项目包含以下操作阶段:
新建基础模块:点击菜单栏
File -> New -> Module,选择创建标准的 Java 模块。
挂载 Web 框架:
方式1:通过以前的
Add Framework Support...双击
Shift查找Add Framework Support...,勾选Web Application选项(可按需指定 Servlet 规范版本并勾选自动生成web.xml)。
方式2:在
Project Structure中创建


配置 Tomcat:

Web 项目目录结构
标准的 JavaWeb 项目遵循固定的物理目录规范,各层级承载明确的职责:
MyWebApp/
├── src/main/java # Java 后台业务源码(Servlet、Filter、Service 等)
├── src/main/resources # 数据库配置文件、日志配置等类路径资源
└── web (或 src/main/webapp) # Web 应用根目录,存放前端静态资源
├── index.jsp # 首页或欢迎文件
└── WEB-INF/ # 受保护的私有目录(外部浏览器无法直接 URL 访问)
├── web.xml # 核心部署描述符(路由映射、初始化参数)
├── classes/ # 编译后的 .class 文件存放地
└── lib/ # 项目私有的第三方依赖 Jar 包WEB-INF 是 JavaEE 规范中强安全隔离区,存放在该目录下的 JSP、HTML 页面只能通过服务端的请求转发(Forward)进行内部跳转,无法被客户端直接发起请求访问。
Web 项目部署
在交付部署前,需在 Project Structure -> Artifacts 中明确构建产物的打包形式。
Tomcat 部署主要涉及两种产物形态:
- war:常规的归档压缩包。系统在构建时将所有类、静态资源和依赖整体打包为单个
.war文件,常用于生产环境交付或跨服务器迁移。 - war exploded:解压形态的目录结构。编译产物直接输出为一个扁平的文件夹,类文件与静态资源按 Web 规范排布。该形态无需反复经历解压与压缩过程,是本地日常开发与实时热更新的首选模式。
热更调试
为了避免修改代码后频繁重启 Tomcat,可在运行配置中利用热更新与断点机制:
配置热更触发策略:进入
Run/Debug Configurations -> Server,定位到两项关键配置:- On 'Update' action:手动点击更新图标或按下快捷键时触发的操作,建议选择
Update classes and resources。 - On frame deactivation:当窗口焦点从 IDEA 切换到浏览器时触发的操作,建议选择
Update classes and resources。

- On 'Update' action:手动点击更新图标或按下快捷键时触发的操作,建议选择
方法体热替换:在 Debug 模式下修改 Java 方法内部代码,执行
Build -> Compile后,JVM 会利用 HotSwap 机制动态加载新字节码,无需重启服务。如果增删了方法、修改了类签名或修改了注解,则必须重新部署。